/**
 * 
 */
package com.pxingg.voice;

import java.util.HashMap;
import java.util.LinkedList;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.pxingg.datetime.TimeUtils;
import com.pxingg.exception.XException;

/**
 * @author pxingg
 * 
 */
public class TTS
{
    private class BackgroundWorker implements Runnable
    {

        /*
         * (non-Javadoc)
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run()
        {
            TTS.log.info("success to start the background worker of TTS");
            while (!isEnd)
            {
                String currentSentence = null;
                synchronized (sentenceList)
                {
                    if (sentenceList.size() > 0)
                    {
                        currentSentence = sentenceList.removeFirst();
                    }
                }

                if (currentSentence == null)
                {
                    // no sentence and sleep 500 ms
                    TimeUtils.mySleep(500);
                    continue;
                }

                trySay(currentSentence);
            }

            TTS.log.info("success to end the background worker of TTS");
        }
    }

    /**
     * The log of this class
     */
    static Log log = LogFactory.getLog(TTS.class);

    /**
     * The Map to store all the voice
     */
    HashMap<String, WavData> metaVoice = new HashMap<String, WavData>();

    /**
     * The sentence list that want to say
     */
    LinkedList<String> sentenceList = new LinkedList<String>();
    /**
     * Need to exist the TTS
     */
    boolean isEnd = false;
    /**
     * The background thread the speaker
     */
    private Thread backgroundWorker = null;

    /**
     * The player for TTS
     */
    private final WavPlayer wavPlayer = new WavPlayer();

    /**
     * The folder sotre the voices
     */
    String VOICES_FOLDER = "D:\\workspace\\SmartHome\\voices\\";

    /**
     * the voice of pingyin
     */
    String metaVoiceName[] = {
        "xing1", "ge1", "ai4", "kong3", "wo3"
    };

    public TTS()
    {
        return;
    }

    /**
     * init TTS system
     * 
     * @throws XException
     */
    public void init() throws XException
    {
        for (int i = 0; i < metaVoiceName.length; i++)
        {
            final WavData wavForWord = new WavData(metaVoiceName[i], VOICES_FOLDER + metaVoiceName[i] + ".wav");
            wavForWord.loadVoices();
            metaVoice.put(metaVoiceName[i], wavForWord);
        }
    }

    /**
     * Try to run TTS
     */
    public void run()
    {
        backgroundWorker = new Thread(new BackgroundWorker());

        backgroundWorker.start();
    }

    /**
     * Add a sentence to a list and let the system begin to speak ouyt it
     * 
     * @param sentence
     */
    public void say(final String sentence)
    {
        synchronized (sentenceList)
        {
            sentenceList.add(sentence);
        }
    }

    /**
     * Try to stop TTS
     */
    public void stop()
    {
        isEnd = true;
    }

    /**
     * Really change the sentence to speaker
     * 
     * @param sentence
     *            the sentence need to say
     */
    public void trySay(final String sentence)
    {
        if (sentence == null)
        {
            return;
        }

        TTS.log.debug("TTS say: " + sentence);

        final String[] words = StringUtils.splitPreserveAllTokens(sentence);
        for (int i = 0; i < words.length; i++)
        {
            if (words[i].equals("\n"))
            {
                // blank , just sleep
                TimeUtils.mySleep(50);
                continue;
            }

            final WavData wavForWord = metaVoice.get(words[i]);

            if (wavForWord == null)
            {
                TTS.log.error("failed to find the wav voice for " + words[i]);
                return;
            }

            try
            {
                wavPlayer.play(wavForWord);
            }
            catch (final XException e)
            {
                TTS.log.error(e);
                TTS.log.error("failed to speaker word " + words[i]);
            }
        }

    }
}
